home *** CD-ROM | disk | FTP | other *** search
- NAME ccsscp
- ; File CCSSCP.ASM
-
- ;CHINESE
- ifdef MSDOS
- include mssscp.dat
- else
- include ccsscp.dat
- endif
-
- code segment public 'code'
-
- extrn comnd:near, clrbuf:near, prtchr:near, outchr:near, sendbr:near
- extrn cptchr:near, serini:near, serrst:near, pcwait:near, katoi:near
- extrn cnvstr:near, getmodem:near, isdev:near, isfile:near
- extrn takrd:near, takclos:near, tolowr:near, prtasz:near,strlen:near
-
- assume cs:code, ds:datas, es:nothing
-
- ; Clear input buffer(s) of serial port
- ; Clear command
- ;
- SCCLR PROC NEAR
- mov kstatus,0 ; global status
- mov ah,cmcfm ; get a confirm
- call comnd
- jmp r ; no confirm
- nop
- call bufclear ; clear our serial port circular buf
- call clrbuf ; clear system serial port buffer too
- jmp rskp ; return success
- SCCLR ENDP
-
- ;
- ; Echo a line of text to our screen
- ; Echo text
- ;
- SCECHO PROC NEAR
- mov ah,cmtxt ; get a whole line of asciiz text
- mov bx,offset line ; where to store in
- mov word ptr [bx],0 ; clear line
- ; mov dx,offset echhlp ; help
- mcmsg echhlp,cechhlp
- call comnd
- jmp rskp ; ignore parse error if no text
- nop
- mov si,offset line ; start of line
- mov di,si ; convert to the same place
- mov ah,script.incasv ; save current case state
- push ax
- mov script.incasv,0ffh ; say no case conversion
- call cnvlin ; convert \numbers to binary
- pop ax
- mov script.incasv,ah ; recover case state
- jc echo3 ; carry set means error
- mov al,lf ; start with a linefeed
- call scdisp ; show it
- jcxz echo2 ; z = nothing to show
- echo1: push cx ; save loop counter
- cld
- lodsb ; get a source char into al
- push si
- call scdisp ; display the char
- pop si
- pop cx
- loop echo1 ; get another
- echo2: jmp rskp ; return success
- echo3: ret ; error
- SCECHO ENDP
-
- ; Extract label from command line. Store in LINE, length in slablen.
- ; Jump to line in Take or Macro following that label.
- GOTO PROC NEAR
- mov kstatus,0 ; global status
- mov ah,cmfile ; get a word
- mov dx,offset line ; buffer to hold label
- mov bx,0 ; no help (non-interactive command)
- mov slablen,bx ; clear label holding buffer
- mov comand.cmkeep,1 ; keep Take/macro open after EOF
- call comnd
- jmp r
- nop
- mov al,ah ; byte count
- mov ah,0
- mov slablen,ax ; save count here
- mov comand.cmkeep,1
- mov ah,cmcfm
- call comnd
- jmp r
- nop
- cmp taklev,0 ; in a Take file or Macro?
- jne GETTO ; ne = yes, find the label
- jmp rskp ; ignore interactive command
-
- ; Find line starting just after ":label". Label is in variable LINE
- ; (length in slablen). Readjust Take read pointer to start of that line.
- ; Performs file search from beginning of file.
- ; Exit carry clear if success, carry set otherwise. Local worker routine.
- getto proc near
- push bx ; global save of bx
- mov bx,takadr
- cmp [bx].taktyp,0ffh ; get type of take (a Macro?)
- je gett2 ; e = yes, a macro
- ; scan from start of Take file
- mov eolchr,LF ; file lines end on LF
- mov bx,[bx].takhnd ; rewind the file
- mov cx,0
- mov dx,0
- mov al,0 ; zero displacement from start of file
- mov ah,lseek
- int dos
- jnc gett1
- jmp gett20 ; c = failure
- gett1: call takrd ; get a buffer of data
- mov bx,takadr ; restore bx to working value
- jmp short gett4
- ; Take a Macro
- gett2: mov eolchr,CR ; Macro lines end on CR
- mov ax,[bx].takptr ; offset of next char to be read
- sub ax,[bx].takbuf ; offset of start of buffer
- dec ax ; omit count byte at start of buffer
- add [bx].takcnt,ax ; original length of text in buffer
- mov ax,[bx].takbuf
- inc ax ; omit count byte at start of buffer
- mov [bx].takptr,ax ; set read pointer to beginning
-
- gett4: call getch ; get a character
- jc gett14 ; c = end of file, no char
- cmp al,':' ; start of label?
- je gett8 ; e = yes
- gett6: cmp al,eolchr ; end of line?
- je gett4 ; e = yes, seek colon for label
- call getch ; get a character
- jc gett14 ; c = end of file, no char
- jmp short gett6 ; read until end of line
- gett8: mov si,offset line ; label to search for
- mov cx,slablen ; its length
- jcxz gett12 ; no chars to match
- cmp byte ptr[si],':' ; user label starts with colon
- jne gett10 ; ne = no
- inc si ; skip user's colon
- dec cx
- jcxz gett12 ; no chars to match
- gett10: call getch ; read file char into al
- jc gett14 ; c = end of file
- mov ah,al
- cld
- lodsb
- call tolowr ; convert al and ah to lower case
- cmp al,ah ; match?
- jne gett6 ; ne = no, goto end of line
- loop gett10 ; continue matching
- ; match obtained
- call getch ; read next file character
- jc gett13 ; c = end of file, no char
- cmp al,' ' ; separator?
- je gett12 ; e = yes, unique label found
- cmp al,eolchr ; or end of line?
- je gett13 ; e = yes
- cmp al,CR ; macro eol, also file start eol pair
- je gett12 ; e = found match
- jmp gett6 ; longer label than target
-
- gett12: call getch ; read past end of line
- jc gett13 ; c = end of file, no char
- cmp al,eolchr ; end of line character?
- jne gett12 ; ne = no, keep reading
- gett13: pop bx
- clc ; return carry clear
- jmp rskp ; Take pointers are ready to read line
-
- gett14: mov ah,prstr ; say label not found
- ; mov dx,offset laberr ; first part of error message
- mcmsg laberr,claberr
- int dos
- mov dx,offset line
- cmp line,':' ; label starts with ":"?
- jne gett15 ; ne = no
- inc dx ; yes, skip it
- gett15: call prtasz ; print asciiz string
- mov ah,prstr
- ; mov dx,offset laberr2 ; trailer of error message
- mcmsg laberr2,claberr2
- int dos
- gett20: pop bx
- mov kstatus,1 ; command status, failure
- stc ; set carry for failure
- ret
- getto endp
- GOTO ENDP
-
- ; Read char from Take buffer. Returns carry clear and char in al, or if end
- ; of file returns carry set. Enter with bx holding takadr. Local worker.
- getch proc near
- cmp [bx].takcnt,0 ; buffer empty?
- jg getch2 ; g = no
- cmp [bx].taktyp,0ffh ; macro?
- je getch1 ; e = yes, that's the end
- call takrd ; read another buffer
- cmp [bx].takcnt,0 ; end of file?
- jne getch2 ; ne = no
- getch1: stc ; e = yes, exit error
- ret
- getch2: push si
- mov si,[bx].takptr ; read a char from Take buffer
- cld
- lodsb
- mov [bx].takptr,si ; move buffer pointer
- pop si
- dec [bx].takcnt ; decrease number of bytes remaining
- clc ; return carry clear
- ret
- getch endp
-
- ; IF [NOT] {ALARM | COUNT | FAILURE | SUCCESS | ERRORLEVEL \number
- ; | EQUAL string string | EXIST filespec} command
-
- IFCMD PROC NEAR
- mov notflag,0 ; assume NOT keyword is absent
- ifcmd1: mov ah,cmkey ; parse keyword
- mov dx,offset iftable ; table of keywords
- mov bx,0 ; help is the table
- call comnd
- jmp r
- nop
- cmp bx,ifnot ; NOT keyword?
- jne ifcmd2 ; ne = no
- xor notflag,1 ; toggle not flag
- jmp short ifcmd1 ; and get next keyword
-
- ifcmd2: cmp bx,ifsuc ; IF SUCCESS?
- jne ifcmd4 ; ne = no
- cmp kstatus,0 ; do we have success?
- jne ifcmdf ; ne = no, no jump
- jmp ifcmdp ; yes
-
- ifcmd4: cmp bx,iferr ; IF ERRORLEVEL?
- jne ifcmd5 ; ne = no
- jmp ifnum ; parse number to binary in line
-
- ifcmd5: cmp bx,ifext ; IF EXIST filespec?
- jne ifcmd6 ; ne = no
- mov ah,cmfile ; read a filespec
- mov dx,offset line ; buffer for filespec
- mov bx,0
- call comnd
- jmp r
- nop
- mov ax,offset line ; isfile wants pointer in ds:ax
- call isfile ; see if file exists
- jc ifcmdf ; c = no
- jmp short ifcmdp ; yes, do following command
-
- ifcmd6: cmp bx,iffail ; IF FAIL?
- jne ifcmd7
- test kstatus,not (0) ; check all bits
- jz ifcmdf ; z = not that condition, no jump
- jmp short ifcmdp
-
- ifcmd7: cmp bx,ifctr ; IF COUNT?
- jne ifcmd8 ; ne = no
- cmp taklev,0 ; in a Take file?
- je ifcmdf ; e = no, fail
- push bx
- mov bx,takadr ; current Take structure
- cmp [bx].takctr,0 ; exhausted count?
- je ifcmd7a ; e = yes, dec no more ye counter
- dec [bx].takctr ; dec COUNT if non-zero
- cmp [bx].takctr,0 ; exhausted now?
- je ifcmd7a ; e = yes
- pop bx
- jmp short ifcmdp ; COUNT > 0 at entry, execute command
- ifcmd7a:pop bx
- jmp short ifcmdf ; do not execute command
-
- ifcmd8: cmp bx,ifmdf ; IF DEF?
- jne ifcmd9 ; ne = no
- jmp ifmdef ; do further parsing below
-
- ifcmd9: cmp bx,ifalarm ; IF ALARM?
- jne ifcmd10 ; ne = no
- jmp ifalrm ; do further parsing below
-
- ifcmd10:cmp bx,ifequal ; IF EQUAL?
- jne ifcmdf ; ne = no
- jmp ifequ ; do further parsing below
- ; Jump points for worker routines
- ; failure
- ifcmdf: cmp notflag,0 ; need to apply not condition?
- jne ifcmdp2 ; ne = yes, take other exit
- ifcmdf2:mov ah,cmtxt ; fail, read and discard rest of line
- mov bx,offset line
- ; mov dx,offset discard ; say not doing anything
- mcmsg discard,cdiscard
- call comnd
- nop
- nop
- nop
- jmp rskp
- ; success (pass)
- ifcmdp: cmp notflag,0 ; need to apply not condition?
- jne ifcmdf2 ; ne = yes, take other exit
- ifcmdp2:jmp rskp ; do command
- IFCMD ENDP
-
- ; Compare errlev against user number. Jump successfully if errlev >= number.
- ; Worker for IF [NOT] ERRORLEVEL number <command>
- ifnum proc near
- mov ah,cmfile ; get following number
- mov dx,offset line+1
- mov line,'\' ; in case user forgets backslash
- mov word ptr line+1,0 ; clear buffer
- ; mov bx,offset ifnhlp ; help
- mcmsgb ifnhlp,cifnhlp
- call comnd
- jmp r
- nop
- mov si,offset line ; put text in compare buffer
- cmp line+1,'\' ; did user include backslash?
- jne ifnum2 ; ne = no
- inc si ; yes, skip our helpful backslash
- ifnum2: call katoi ; convert number to binary in ax
- jc ifnum4 ; c = failed to convert a number
- cmp errlev,al ; at or above this level?
- jae ifnum3 ; ae = yes, succeed
- jmp ifcmdf ; else fail
- ifnum3: jmp ifcmdp ; jump to main command Success exit
-
- ifnum4: mov dx,offset line+1 ; pointer to bad word
- mov tempd,dx ; remember starting place for text
- call strlen ; get its length
- add dx,cx ; skip over current word
- mov bx,dx
- mov byte ptr [bx],' ' ; space, chopped by parser
- inc bx ; new text goes here
- mov dx,0 ; help
- mov ah,cmtxt ; read rest of line
- call comnd
- jmp r
- nop
- cmp ah,0 ; returned byte count
- ja ifnum5 ; a = got some
- mov byte ptr[bx-1],0 ; remove space separator from above
- ifnum5: mov ah,prstr
- ; mov dx,offset ifnmsg ; error message header
- mcmsg ifnmsg,cifnmsg
- int dos
- mov dx,offset line+1 ; start of user text
- call prtasz ; display asciiz string
- mov ah,prstr
- mov dx,offset ifnmsg2 ; trailer of message
- int dos
- jmp ifcmdf ; jump to main command Failure exit
- ifnum endp
-
- ; Process IF [NOT] DEF <macro name> <command>
- ifmdef proc near
- mov dx,offset line+1 ; point to work buffer
- ; mov bx,offset ifdfhlp ; help
- mcmsgb ifdfhlp,cifdfhlp
- mov ah,cmfile ; get macro name
- mov comand.cmper,1 ; do not react to \%x
- call comnd
- jmp r
- nop
- mov line,ah ; store length in buffer
- ifmde2: mov bx,offset mcctab+1 ; table of macro keywords
- mov tempd,0 ; tempd = current keyword
- cmp byte ptr [bx-1],0 ; any macros defined?
- je ifmde9 ; e = no, failure, exit now
- ; match table keyword and user word
- ifmde3: mov si,offset line ; pointer to user's cnt+name
- mov cl,[si] ; length of user's macro name
- xor ch,ch
- inc si ; point to macro name
- cmp cl,[bx] ; compare length vs table keyword
- jne ifmde7 ; ne = not equal lengths, try another
- push si ; lengths match, how about spelling?
- push bx
- inc bx ; point at start of keyword
- ifmde4: mov ah,[bx] ; keyword char
- mov al,[si] ; new text char
- cmp al,'a' ; map lower case to upper
- jb ifmde5
- cmp al,'z'
- ja ifmde5
- sub al,'a'-'A'
- ifmde5: cmp al,ah ; test characters
- jne ifmde6 ; ne = no match
- inc si ; move to next char
- inc bx
- loop ifmde4 ; loop through entire length
- ifmde6: pop bx
- pop si
- jcxz ifmde10 ; z: cx = 0, found the name
- ; select next keyword
- ifmde7: inc tempd ; number of keyword to test next
- mov cx,tempd
- cmp cl,mcctab ; all done? Recall, tempd starts at 0
- jae ifmde9 ; ae = yes, no match
- ifmde8: mov al,[bx] ; cnt (keyword length from macro)
- xor ah,ah
- add ax,4 ; skip over '$' and two byte value
- add bx,ax ; bx = start of next keyword slot
- jmp short ifmde3 ; do another comparison
- ifmde9: jmp ifcmdf ; jump to main command Failure exit
- ifmde10:jmp ifcmdp ; jump to main command Success exit
- ifmdef endp
-
- ; IF [not] ALARM hh:mm:ss command
- ifalrm proc near
- call chkkbd ; check keyboard for override
- test status,stat_cc ; Control-C?
- jz ifalr1 ; z = no
- ret ; yes, return failure now
- ifalr1: push word ptr timhms
- push word ptr timhms+2 ; save working timeouts
- mov ax,word ptr alrhms
- mov word ptr timhms,ax
- mov ax,word ptr alrhms+2
- mov word ptr timhms+2,ax ; set alarm value
- call chktmo ; check for timeout
- pop word ptr timhms+2 ; restore working timeouts
- pop word ptr timhms
- test status,stat_tmo ; tod past user time (alarm sounded)?
- jnz ifalr4 ; nz = yes, succeed
- ; failure (not at alarm time yet)
- ifalr2: cmp notflag,0 ; need to apply not condition?
- jne ifalr5 ; ne = yes, take other exit
- ifalr3: mov ah,cmtxt ; fail, read and discard rest of line
- mov bx,offset line
- mov dx,0
- call comnd
- jmp r
- nop
- jmp rskp
- ; success (at or past alarm time)
- ifalr4: cmp notflag,0 ; need to apply not condition?
- jne ifalr3 ; ne = yes, take other exit
- ifalr5: jmp rskp ; pass, do command
- ifalrm endp
-
- ; IF [NOT] EQUAL word word command
- ; Permits use of \number, {string}, @filespec
- ifequ proc near
- mov ah,cmfile ; get a word
- mov dx,offset line ; where to store
- mov line,0 ; clear first entry
- ; mov bx,offset ifehlp1 ; help
- mcmsgb ifehlp1,cifehlp1
- call comnd
- jmp rskp ; ignore parse error if no text
- nop
- mov si,offset line ; start of line
- mov di,si ; convert to the same place
- call cnvlin ; convert \numbers to binary
- jc ifequ9 ; carry set means error
- jcxz ifequ9 ; z = empty word
- mov tempa,0 ; line length, so far
- cld
- ifequ1: lodsb
- cmp al,' ' ; space or control code?
- jbe ifequ2 ; be = yes, end of word
- inc tempa ; count char in word
- loop ifequ1 ; continue
- ifequ2: mov byte ptr[si],0 ; plant terminator
- inc si ; skip null terminator
- mov temptr,si ; place to start second part
- mov dx,si
- mov word ptr[si],0 ; clear second part
- mov ah,cmfile ; get a word of text
- ; mov bx,offset ifehlp2 ; help
- mcmsgb ifehlp2,cifehlp2
- call comnd
- jmp rskp ; ignore parse error if no text
- nop
- mov si,temptr ; start of second line
- mov di,si ; convert to the same place
- call cnvlin ; convert \numbers to binary
- jc ifequ9 ; carry set means error
- jcxz ifequ9 ; z = empty word
- mov si,temptr ; point at second word
- mov dx,0 ; word length so far
- cld
- ifequ3: lodsb
- cmp al,' ' ; space or control code?
- jbe ifequ4 ; be = yes, end of word
- inc dx ; count char in word
- loop ifequ3 ; continue
- ifequ4: mov byte ptr[si],0 ; plant terminator
- mov cx,dx ; length of second word
- cmp tempa,dl ; same lengths?
- jne ifequ9 ; ne = no
- jcxz ifequ9 ; both are null
- push es
- push ds
- pop es
- mov si,offset line ; first word
- mov di,temptr ; second word
- cld
- repe cmpsb ; see if they are the same
- pop es
- jne ifequ9 ; ne = not the same, fail
- jmp ifcmdp ; do IF cmd success
- ifequ9: jmp ifcmdf ; do IF cmd failure
- ifequ endp
-
- ; SET ALARM <time, sec from now or HH:MM:SS>
- SETALRM PROC NEAR
- mov dx,offset line ; point to work buffer
- mov word ptr line,0
- mov word ptr line+2,0
- ; mov bx,offset alrmhlp ; help
- mcmsgb alrmhlp,calrmhlp
- mov ah,cmfile ; get macro name
- call comnd
- jmp r
- nop
- mov ah,cmcfm ; get a confirm
- call comnd
- jmp r
- nop
- push word ptr timhms
- push word ptr timhms+2 ; save working timeouts
- mov si,offset line ; source pointer
- call inptim ; get the timeout time, sets si
- mov ax,word ptr timhms ; save time in alarm area
- mov word ptr alrhms,ax
- mov ax,word ptr timhms+2
- mov word ptr alrhms+2,ax
- pop word ptr timhms+2 ; restore working timeouts
- pop word ptr timhms
- jmp rskp
- SETALRM ENDP
-
- ; REINPUT <timeout> <match text>
- ; Reread material in serial port buffer, seeking a match with user's text
- ; pattern. If user's pattern is longer than material in buffer then read
- ; additional characters from the serial port. Use SCINP to do the main work.
-
- SCREINP PROC NEAR
- mov reinflg,1 ; say doing REINPUT, not INPUT
- jmp short input10
- SCREINP ENDP
-
- ; Input from port command, match input with text pattern
- ; Input [timeout] text
- ;
- SCINP PROC NEAR
- mov reinflg,0 ; say doing INPUT, not REINPUT
- jmp short input10
-
- input10:mov kstatus,0
- mov ah,cmtxt ; get a whole line of asciiz text
- mov bx,offset line ; place to put text
- ; mov dx,offset inphlp ; help message
- mcmsg inphlp,cinphlp
- call comnd ; get the pattern text
- jmp r ; nothing, complain
- nop
- cmp reinflg,0 ; Input command?
- jne input1 ; ne = no, Reinput
- cmp taklev,0 ; are we in a Take file?
- je input0 ; e = no, display linefeed
- cmp flags.takflg,0 ; are Take commands being echoed?
- je input1 ; e = no, skip display
- input0: cmp script.inecho,0 ; Input echo off?
- je input1 ; e = yes
- mov al,lf ; next line
- call scdisp ; display the char
- input1: call serini ; initialize the system's serial port
- jc input1a ; c = failure
- mov status,stat_unk ; clear status flag
- mov si,offset line ; source pointer
- call inptim ; get the timeout time, sets si
- jnc input1b ; nc = legal time value or none
- input1a:jmp input5 ; else fail on error
- input1b:mov di,offset line ; put text in compare buffer
- call cnvlin ; convert \numbers in buf line
- mov inplen,cx ; cx = number of bytes in final string
- mov parmsk,0ffh ; parity mask, assume 8 bit data
- mov di,portval
- cmp [di].parflg,parnon ; parity is none?
- je input1c ; e = none
- mov parmsk,07fh ; else strip parity (8th) bit
- input1c:mov di,offset line
- mov temptr,di ; pointer to pattern char
- mov temptr2,di ; and we need pointer to end of string
- add temptr2,cx ; offset of end of string
- ; setup reinput read pointer & count
- mov ax,bufwtptr ; where next new char goes
- mov bufpkptr,ax ; set peek-read pointer at oldest char
- mov bufpkcnt,prtbuflen ; always look back one full buffer
- ; see if a pattern needs matching
- cmp inplen,0 ; empty pattern? (cnvlin sets cx=cnt)
- jne input4 ; ne = not empty
- cmp reinflg,0 ; Input command?
- je input3 ; e = yes, read and discard chars
- jmp input5 ; reinput, just exit timeout
-
- ; empty. read, display, and discard
- input3: call chkkbd ; check keyboard
- test status,stat_cc ; did user type control-c?
- jnz input5 ; nz = yes, quit
- test status,stat_cr ; did user type cr? [js]
- jz input3a ; z = no
- jmp inputx ; nz = yes, return success [js]
- input3a:call chktmo ; check timeout
- test status,stat_tmo
- jnz input5 ; nz = timed out, quit
- call bufread ; read from serial port buffer into al
- jmp input3 ; loop until timeout, exit timeout
-
- ; start main read and compare loop
- input4: mov di,temptr ; pointer to current pattern char
- cmp di,temptr2 ; at end of pattern?
- jae inputx ; ae = yes, return success
- call chkkbd ; check keyboard
- test status,stat_cc ; did user type control-c?
- jnz input5 ; nz = yes, quit
- test status,stat_cr ; did user type cr? [js]
- jz input4a ; z = no
- jmp inputx ; nz = yes, return success [js]
- input4a:call chktmo ; check timeout
- test status,stat_tmo+stat_ok ; timeout or user override
- jnz input5 ; nz = timed out, quit
- cmp reinflg,0 ; Input command?
- jne input4b ; ne = no, a reinput cmd
- call bufread ; read from serial port buffer into al
- jc input4 ; c = nothing there, keep looking
- jmp short input4c ; analyze character
- input4b:call peekbuf ; reinput: peek-read from buffer
- jc input4 ; c = failed to get a character
- ; got a char from buffer/port
- input4c:cmp al,'a' ; candidate for case conversion? [js]
- jb input4d ; b = no [js]
- cmp al,'z' ; in lower case set? [js]
- ja input4d ; a = no [js]
- and al,script.incasv ; apply case conversion mask
- input4d:mov di,temptr
- mov ah,byte ptr [di] ; get current pattern char again
- call matchr ; al=rcvd, ah=pattern, do they match?
- jc inpm ; c = no match, try substring
- inc temptr ; matched, point to next pattern char
- jmp input4
- input5: or errlev,2 ; set RECEIVE failure condition
- or fsta.xstatus,2 ; set status
- cmp reinflg,0 ; Input command?
- jne input6 ; ne = no
- jmp squit ; exit failure: timeout or control-c
- input6: mov kstatus,2 ; failure
- jmp squit1 ; skip timeout message, if any
- inputx: jmp rskp ; return success
- ; See if a trailing-subset of the matched chars + new port char can match
- ; the beginning part of the pattern. That is, if we were to simply "forget"
- ; the oldest of the matched chars and slide left the apparent port string
- ; then could we eventually find a match? Example: "Input 10 memema"
- ; gives the pattern of "memema"; suppose the received chars were "mememema".
- ; Forgetting one left-most rcv'd char at a time (two in this case) finally
- ; yields a match, from which we should continue to compare fresh port chars
- ; with successive pattern chars until either they match through all pattern
- ; chars or we encounter another break. If there is a later break, repeat this
- ; algorithm.
- ; Since we really have only the latest char from the port then pointers to
- ; the matched pattern chars are used to mimic the earlier received chars:
- ; they must have been identical to produce a match to date. The quick way
- ; to "forget" oldest received chars is to scan backward through the matched
- ; pattern chars looking for the current port char; if the first such find does
- ; not yield a matching substring then look back further.
- ; no or partial match then break
- ; di = temptr = pattern break char
- ; al = port char causing break
- ; di - offset line = # chars matched thus far
- ; avoid cpu-brand side effects with "repne scasb"
- inpm: mov tempa,al ; save port char here
- inpm1: mov tempd,di ; pattern break loc, where matching failed
- mov cx,di ; char at di does not match current port char
- sub cx,offset line ; compute count of matched bytes
- jcxz inpm4 ; z = 0 = mismatch on the initial pattern char
-
- mov al,tempa ; port char to find (in case we looped here)
- inpm2: dec di ; back up one pattern char
- mov ah,byte ptr [di]; current pattern character to consider
- call matchr ; is port char = earlier pattern char? [js]
- jnc inpm3 ; nc = equal values, go construct substring
- loop inpm2 ; do cx times, max. (length of match to date)
- jmp inpm4 ; get here when there are no matches [js]
-
- inpm3: mov bx,tempd ; get last break location
- sub bx,di ; displacement = break - new find of port char
- mov tempd,di ; remember new location of a port-like char
- ; cx has number of chars in test substring
- dec cx ; matched one char already [jrs]
- jcxz inpm3a ; is there anything left? [jrs]
- call matstr ; does this substring match the pattern?
- jc inpm1 ; c = no match, try making substring smaller
-
- inpm3a: mov di,tempd ; sub-string matched. Use this shorter match
- mov temptr,di ; set di for exit (matstr messes up di)
- inc temptr ; matched, point to next pattern char
- jmp input4 ; continue with fresh port info
-
- inpm4: mov temptr,offset line; complete failure, restart scanning
- jmp input4 ; get something from the port
-
- ; worker for SCINP
- ; compare strings. One starts at offset line, the other starts bx bytes later.
- ; cx = # chars to compare. Return carry clear if match, else carry set.
- matstr: mov si,offset line ; start of pattern string
- matstr1:mov ah,byte ptr [si] ; pattern char
- mov al,byte ptr [si+bx] ; "old port char" (same as pattern char)
- call matchr ; check match of these two characters
- jc matstr2 ; c = no match (exit with carry flag set)
- inc si ; match, consider next pair
- loop matstr1 ; consider rest of substring (cx is counter)
- clc ; clear c bit (substrings do match)
- matstr2:ret ; preserves flags (c set = no match)
-
- ; worker for SCINP
- ; compare single characters, one in ah and the other in al. Allow the 0ffh
- ; wild card to match CR and LF individually. Return carry clear if match,
- ; or carry set if they do not match. Registers preserved.
- matchr: cmp ah,al ; do these match?
- je matchr6 ; e = yes
- cmp ah,0ffh ; the match cr/lf indicator?
- je matchr2 ; e = yes
- cmp al,0ffh ; the match cr/lf indicator?
- jne matchr5 ; ne = no match at all.
- matchr2:push ax ; save both chars again
- and ah,al ; make a common byte for testing
- cmp ah,cr
- je matchr4 ; e = cr matches 0ffh
- cmp ah,lf
- je matchr4 ; e = lf matches 0ffh
- pop ax ; recover chars
- matchr5:stc ; set carry (no match)
- ret
- matchr4:pop ax ; recover chars
- matchr6:clc ; clear carry (match)
- ret
- SCINP ENDP
- ;
- ; Pause for the specified number of seconds or until a time of day
- ; Pause [seconds or hh:mm:ss]
- ;
- SCPAU PROC NEAR
- mov kstatus,0
- mov ah,cmfile ; get a word (number)
- mov dx,offset line ; where to store it
- mov byte ptr line,0 ; terminate line incase no text
- ; mov bx,offset ptshlp ; help msg
- mcmsgb ptshlp,cptshlp
- call comnd
- jmp r
- nop ; must be at least 3 bytes
- mov ah,cmcfm ; get a confirm
- call comnd
- jmp r
- nop
- mov si,offset line ; source pointer
- call inptim ; parse pause time (or force default)
- jc scpau1 ; c = bad time value
- mov tempa,0 ; no modem status to detect
- jmp swait4 ; finish in common code
- scpau1: ret
- SCPAU ENDP
-
- ;
- ; Wait for the indicated signal for the specified number of seconds or tod
- ; WAIT [seconds] \signal where \signal is \cd, \dsr modem status lines.
- ; Use INPUT-TIMEOUT ACTION for failures.
- ;
- SCWAIT PROC NEAR
- mov kstatus,0
- mov ah,cmtxt ; get a word (number)
- mov bx,offset line ; where to store it
- mov byte ptr line,0 ; terminate line incase no text
- ; mov dx,offset wthlp ; help msg
- mcmsg wthlp,cwthlp
- call comnd
- jmp r
- nop ; must be at least 3 bytes
- mov tempa,0 ; clear modem status test byte
- mov si,offset line ; source pointer
- call inptim ; parse pause time (or force default)
- jc swait1a ; c = bad time value
- mov di,offset line ; put text in compare buffer
- call cnvlin ; convert \numbers in buf line
- mov si,di ; code below uses si
- jnc swait1 ; nc = no error
- swait1a:ret ; else return on error
- swait1: cmp cx,0 ; number of chars to examine
- jle swait4 ; le = none
- cld
- lodsb ; get a character
- dec cx ; reduce count remaining
- cmp al,' ' ; white space?
- jbe swait1 ; be = yes, skip over it
- cmp al,'\' ; backslash signal introducer?
- jne swait1 ; ne = no, keep searching
- cmp cx,2 ; at least two chars in signal?
- jl swait3 ; l = no
- mov ax,[si]
- or ax,2020h ; upper case to lower, two chars
- cmp ax,'dc' ; carrier detect?
- jne swait2 ; ne = no, try next signal
- or tempa,modcd ; look for the CD bit
- add si,2 ; skip this field
- sub cx,2 ; three less chars left in the line
- jmp short swait1 ; continue the scan
- swait2: cmp ax,'sd' ; data set ready?
- jne swait3 ; ne = no
- mov al,[si+2] ; third letter
- or al,20h ; to lower case
- cmp al,'r' ; r for dsr?
- jne swait3 ; ne = no
- or tempa,moddsr ; look for the DSR bit
- add si,3 ; skip this field
- sub cx,3 ; four less chars left in the line
- swait3: cmp ax,'tc' ; clear to send?
- jne swait3a ; ne = no
- mov al,[si+2] ; third letter
- or al,20h ; to lower case
- cmp al,'s' ; r for dsr?
- jne swait3a ; ne = no
- or tempa,modcts ; look for the CTS bit
- add si,3 ; skip this field
- sub cx,3 ; four less chars left in the line
- swait3a:jmp short swait1 ; continue the scan
- ; SWAIT4 is used by PAUSE command
- SWAIT4: cmp taklev,0 ; are we in a Take file
- je swait5 ; e = no, print linefeed
- cmp flags.takflg,0 ; are commands being echoed
- je swait6 ; e = no, skip this
- swait5: cmp script.inecho,0 ; Input echoing off?
- je swait6 ; e = yes
- mov al,lf ; next line
- call scdisp ; display the char
- swait6: call serini ; initialize the system's serial port
- jc swait9 ; c = failure
- mov status,stat_unk ; clear status flag
- push si
- mov parmsk,0ffh ; parity mask, assume 8 bit data
- mov si,portval
- cmp [si].parflg,parnon ; parity is none?
- pop si
- je swait7 ; e = none
- mov parmsk,07fh ; else strip parity (8th) bit
- swait7: call getmodem ; modem handshake status to AL
- and al,tempa ; keep only bits to be tested
- cmp tempa,0 ; anything to be tested?
- je swait7a ; e = no, just do the wait part
- cmp al,tempa ; check selected status bits
- jne swait7a ; ne = not all selected bits match
- jmp rskp ; all match. take successful exit
- swait7a:call chkport ; get and show any new port char
- call chkkbd ; check keyboard
- test status,stat_cc ; control-c?
- jnz swait9 ; nz = yes, quit
- call chktmo ; check tod for timeout
- test status,stat_tmo+stat_ok ; timeout or user override?
- jz swait7 ; z = no, continue to wait
- cmp tempa,0 ; were we waiting on anything?
- jne swait9 ; ne = yes, timeout = failure
- jmp rskp ; else timeout = success
- swait9: or errlev,2 ; set RECEIVE error condx
- or fsta.xstatus,2 ; set status
- jmp squit ; take error exit
- SCWAIT ENDP
-
-
- ; Output line of text to port, detect \b and \B as commands to send a Break
- ; on the serial port line.
- ; Output text
-
- SCOUT PROC NEAR
- mov kstatus,0
- mov ah,cmtxt ; get a whole line of asciiz text
- mov bx,offset line ; store text here
- ; mov dx,offset outhlp ; help message
- mcmsg outhlp,couthlp
- call comnd
- jmp r
- nop
- cmp taklev,0 ; is this being done in a Take file?
- je outpu0 ; e = no, display linefeed
- cmp flags.takflg,0 ; are commands being echoed?
- je outp0a ; e = no, skip the display
- outpu0: cmp script.inecho,0 ; Input echoing off?
- je outp0a ; e = yes
- mov al,lf ; next line
- call scdisp ; display the char
- outp0a: mov al,spause ; wait three millisec or more
- add al,3
- xor ah,ah
- call pcwait ; breathing space for HDX systems
- call serini ; initialize the system's serial port
- jnc outp0c ; nc = success
- or errlev,1 ; set SEND failure condition
- or fsta.xstatus,1 ; set status
- jmp squit
-
- outp0c: mov status,stat_unk ; clear status flag
- mov parmsk,0ffh ; parity mask, assume 8 bit data
- mov si,portval
- cmp [si].parflg,parnon ; parity is none?
- je outp0b ; e = none
- mov parmsk,07fh ; else strip parity (8th) bit
- outp0b: mov si,portval ; serial port structure
- mov bl,[si].ecoflg ; Get the local echo flag
- mov lecho,bl ; our copy
- mov si,offset line ; get start of line
- mov di,offset line ; put results in the same place
- mov ah,script.incasv ; save current case state
- push ax
- mov script.incasv,0ffh ; say no case conversion
- call cnvlin ; convert \numbers to binary
- pop ax
- mov script.incasv,ah ; recover case state
- jnc outpu1 ; nc = no error
- ret ; return on error
- outpu1: mov temptr,offset line ; save pointer here
- mov tempd,cx ; save byte count here
- mov ttyact,1 ; say interactive style output
-
- outpu2: cmp tempd,0 ; are we done?
- jg outpu2a ; g = not done yet
- mov ttyact,0 ; reset interactive output flag
- jmp rskp ; return success
- outpu2a:mov si,temptr ; recover pointer
- cld
- lodsb ; get the character
- dec tempd ; one less char to send
- mov temptr,si ; save position on line
- mov tempa,al ; save char here for outchr
- mov retry,0 ; number of output retries
- cmp al,5ch ; backslash?
- jne outpu4d ; ne = no
- cmp byte ptr [si],'b' ; "\b" for Break?
- je outpu4c ; e = yes
- cmp byte ptr [si],'B' ; "\B" ?
- jne outpu4d ; ne = no
- outpu4c:inc temptr ; move scan ptr beyond "\b"
- dec tempd
- call sendbr ; call msx send-a-break procedure
- jmp outpu5 ; resume beyond echoing
-
- outpu4d:inc retry ; count output attempts
- cmp retry,maxtry ; too many retries?
- jle outpu4g ; le = no
- or errlev,1 ; set SEND failure condition
- or fsta.xstatus,1 ; set status
- jmp squit ; return failure
- outpu4g:mov ah,tempa ; outchr gets fed from ah
- call outchr ; send the character to the port
- jmp outpu4d ; failure to send char
- nop ; ensure 3 bytes for rskp of outchr
- cmp lecho,0 ; is Local echo active?
- je outpu5 ; e = no
- mov al,tempa ;
- test flags.capflg,logses ; is capturing active?
- jz outp4b ; z = no
- push ax ; save char
- call cptchr ; give it captured character
- pop ax ; restore character and keep going
- outp4b: cmp script.inecho,0 ; Input echo off?
- je outpu5 ; e = yes
- call scdisp ; echo character to the screen
- ;
- outpu5: push cx
- outpu5a:mov cx,10 ; reset retry counter
- outpu5b:call chkkbd ; check keyboard for interruption
- test status,stat_cc ; control c interrupt?
- jnz outpu6 ; nz = yes, quit now
- cmp script.inecho,0 ; Input echo off?
- je outpu5c ; e = yes, skip port reading/display
- call chkport ; check for char at serial port
- test status,stat_ok ; and put any in buffer
- jnz outpu5a ; nz = have a char, look for another
- mov ax,1 ; wait 1 millisec between rereads
- push cx ; protect counter
- call pcwait
- pop cx
- dec cx ; count down retries
- jge outpu5b ; ge = keep trying
- outpu5c:pop cx ; no more input, recover register
- jmp outpu2 ; resume command
- outpu6: pop cx ; recover register
- or errlev,1 ; set SEND failure condition
- or fsta.xstatus,1 ; set status
- mov ttyact,0 ; reset interactive output flag
- jmp squit ; quit on control c
- SCOUT ENDP
-
-
- ; Raw file transfer to host (strips linefeeds)
- ; Transmit filespec [prompt]
- ; Optional prompt is the single char expected from the host to ACK each line.
- ; Default prompt is a linefeed (or a carriage return from us).
- ;
- SCXMIT PROC NEAR
- mov kstatus,0
- mov ah,cmfile ; get a filename, asciiz
- mov dx,offset line ; where to store it
- ; mov bx,offset xmthlp ; help message
- mcmsgb xmthlp,cxmthlp
- call comnd
- jmp r ; exit on failure
- nop
- mov ah,cmtxt ; get a prompt string, asciiz
- mov bx,offset line+80 ; where to keep it (end of "line")
- mov word ptr [bx],0 ; clear and add terminator
- ; mov dx,offset pmthlp ; Help in case user types "?".
- mcmsg pmthlp,cpmthlp
- call comnd
- jmp r
- nop
- cmp line,0 ; filename given?
- je xmit0a ; e = no
- cmp ah,0 ; prompt given?
- je xmit0b ; e = no, use line feed default
- mov si,offset line+80 ; convert possible numeric prompt
- call katoi ; convert number to binary, if number
- jnc xmit0 ; nc = got number
- mov al,line+80 ; get ascii char from user's prompt
- jmp short xmit0
- xmit0b: mov al,lf ; default prompt
- xmit0: mov tempa,al ; save the code here
- mov dx,offset line ; point to filename
- mov ah,open2 ; DOS 2 open file
- mov al,0 ; open for reading
- int dos
- mov fhandle,ax ; store file handle here
- jnc xmit1 ; nc = successful opening
-
- xmit0a: mov ah,prstr ; give file not found error message
- ; mov dx,offset xfrfnf
- mcmsg xfrfnf,cxfrfnf
- int dos
- or errlev,1 ; set SEND failure condition
- or fsta.xstatus,1 ; set status
- jmp squit ; exit failure
-
- xmitx: mov ah,prstr ; error during transfer
- ; mov dx,offset xfrrer
- mcmsg xfrrer,cxfrrer
- int dos
- xmitx2: mov bx,fhandle ; file handle
- mov ah,close2 ; close file
- int dos
- ;; call serrst ; reset serial port
- call bufclear ; clear script buffer
- call clrbuf ; clear local serial port buffer
- or errlev,1 ; set SEND failure condition
- or fsta.xstatus,1 ; set status
- jmp squit ; exit failure
- ;
- xmity: mov bx,fhandle ; file handle
- mov ah,close2 ; close file
- int dos
- ;; call serrst ; reset serial port
- call bufclear ; clear buffers
- call clrbuf
- jmp rskp ; and return success
-
- xmit1: call serini ; initialize serial port
- jnc xmit1b ; nc = success
- or errlev,1 ; set SEND failure condition
- or fsta.xstatus,1 ; set status
- jmp squit
-
- xmit1b: call bufclear ; clear script input buffer
- call clrbuf ; clear serial port buffer
- mov status,stat_unk ; clear status flag
- mov parmsk,0ffh ; parity mask, assume 8 bit data
- mov si,portval
- cmp [si].parflg,parnon ; parity is none?
- je xmit1a ; e = none
- mov parmsk,07fh ; else strip parity (8th) bit
- xmit1a: mov bl,[si].ecoflg ; Get the local echo flag.
- mov lecho,bl ; our copy
- mov dx,offset crlf ; display cr/lf
- mov ah,prstr
- int dos
-
- xmit2: mov dx,offset line ; buffer to read into
- mov cx,linelen ; # of bytes to read
- mov ah,readf2 ; read bytes from file
- mov bx,fhandle ; file handle is stored here
- int dos
- jnc xmit2a ; nc = success
- jmp xmitx ; exit failure
- xmit2a: mov cx,ax ; number of bytes read
- jcxz xmity ; z = none, end of file
- ;
- mov si,offset line ; buffer for file reads
- cld
- xmit3: lodsb ; get a byte
- cmp al,ctlz ; is this a Control-Z?
- jne xmit3a ; ne = no
- cmp flags.eofcz,0 ; ignore Control-Z as EOF?
- jne xmity ; ne = no, we are at EOF
- xmit3a: push si ; save position on line
- push cx ; and byte count
- push ax ; save char around outchr call
- xmit4: mov retry,0 ; clear retry counter
- xmit4f: pop ax ; recover saved char
- push ax ; and save it again
- mov ah,al ; outchr wants char in ah
- inc retry ; count number of attempts
- cmp retry,maxtry ; too many retries?
- jle xmit4g ; le = no
- or status,stat_cc ; simulate control-c abort
- pop ax ; clean stack
- xor al,al ; clear char
- jmp xmita ; and abort transfer
- xmit4g: cmp al,lf ; line feed?
- je xmit4h ; e = yes, don't send it
- call outchr ; send the character to the port
- jmp xmit4f ; failed, try again
- nop
- xmit4h: pop ax ; recover saved char
- cmp lecho,0 ; is local echoing active?
- je xmit5 ; e = no
- test flags.capflg,logses ; capturing active?
- jz xmit4a ; z = no
- push ax ; save char
- call cptchr ; give it the character just sent
- pop ax ; restore character and keep going
- xmit4a: call scdisp ; display char on screen
-
- xmit5: cmp al,cr ; did we send a carriage return?
- je xmit8 ; e = yes, time to check keyboard
-
- xmit7: pop cx
- pop si
- loop xmit3 ; finish this buffer full
- jmp xmit2 ; read next buffer
-
- xmit8: test status,stat_cc ; Control-C seen?
- jnz xmita ; nz = yes
- call chkkbd ; check keyboard (returns char in al)
- test status,stat_ok ; have a char?
- jnz xmita ; nz = yes
- cmp tempa,0 ; is prompt char a null?
- jne xmit8b ; ne = no
- call bufread ; check for char from serial port buf
- jnc xmit8 ; nc = a char, read til none
- jmp xmit7 ; continue transfer
- xmit8b: call bufread ; check for char from serial port buf
- jc xmit8 ; c = none
- cmp al,tempa ; is port char the ack?
- jne xmit8 ; ne = no, just ignore the char
- jmp xmit7 ; yes, continue transfer
-
- xmita: test status,stat_cc ; control-c?
- jnz xmitc ; nz = yes
- test status,stat_cr ; a local ack?
- jz xmit8 ; no, ignore local char
- mov dx,offset crlf ; display cr/lf
- mov ah,prstr
- int dos
- jmp xmit7 ; continue transfer
- xmitc: pop cx ; Control-C, clear stack
- pop si ; ...
- ; mov dx,offset xfrcan ; say canceling transfer
- mcmsg xfrcan,cxfrcan
- mov ah,prstr
- int dos
- mov flags.cxzflg,0 ; clear Control-C flag
- jmp xmitx2 ; ctrl-c, quit
-
- SCXMIT ENDP
-
- ;;;;;;;;;;;;;;;;;; local support procedures ;;;;;;;;;;
- ;
- ;worker: copy line from si to di, converting \nnn strings to single chars
- ; returns carry set if error, else carry clear. Detects leading at-sign
- ; as an indicator to read command file for one line of text; command files
- ; may be nested to a depth of 100.
- ; Items of the form \chars which are not numbers are copied verbatium
- ; to the output string (ex: \a is copied as \a). The string is first trimmed
- ; of trailing spaces, then the possible curly brace delimiter pair is
- ; removed, and finally \numbers are converted to binary. [jrd]
- cnvlin proc near
- push si ; source ptr
- push di ; destination ptr
- push ax
- mov ax,ds
- mov es,ax ; use data segment for es:di
- pop ax
- mov tempd,0 ; count indirection depth
- cnvln0: cmp tempd,100 ; limit to 100 deep
- jbe cnvln0a ; be = not too deep yet
- jmp cnvln8 ; too deep, quit
- cnvln0a:cld
- xor cx,cx ; initialize returned byte count
- lodsb ; get the first character
- cmp al,40h ; at-sign indirection?
- je cnvln5 ; e = yes, open the file
- dec si ; no, push back char just read
- call cnvstr ; convert string's curly braces
- cnvln1: xor ah,ah ; clear high byte of number
- call katoi ; get a char into al, convert number
- jnc cnvln4 ; nc = binary number converted
- cmp al,0ffh ; cr/lf wild card?
- je cnvln4 ; e = yes, store it
- cmp al,0 ; end of line?
- jne cnvln3 ; ne = no
- jmp cnvlnx ; yes, exit now
- cnvln3: cmp al,'a' ; candidate for conversion? [js]
- jb cnvln4 ; b = no
- cmp al,'z' ; still in lower case set? [js]
- ja cnvln4 ; a = no
- and al,script.incasv ; else apply case conversion mask
- cnvln4: stosb ; save the char
- inc cx ; and count it
- cmp ah,0 ; was number larger than one byte?
- je cnvln1 ; e = no
- xchg ah,al ; put high byte into al
- stosb ; store it too
- inc cx ; count storage
- jmp short cnvln1 ; read more
-
- cnvln5: mov dx,si ; get filename ptr from source line
- push si
- inc tempd ; count indirection depth
- mov cx,64 ; max length of a filename.
- cnvln5a:cmp byte ptr [si],' ' ; whitespace or control code?
- jbe cnvln5b ; be = yes, found termination
- inc si ; else look at next char
- loop cnvln5a ; limit search
- cnvln5b:mov byte ptr [si],0 ; make asciiz
- pop si
- mov ah,open2 ; DOS 2 open file
- mov al,0 ; open for reading
- int dos
- mov word ptr fhandle,ax ; store file handle
- jnc cnvln7 ; nc = open ok, read from file
-
- mov ah,prstr
- ; mov dx,offset indmis ; file open error msg
- mcmsg indmis,cindmis
- int dos
- xor cx,cx ; say zero bytes read
- pop di ; destination ptr
- pop si ; source ptr
- stc ; set c bit, failure
- ret
-
- cnvln7: mov bx,word ptr fhandle ; file handle
- mov cx,linelen ; # of bytes to read
- mov ah,ioctl ; ioctl, is this the console device?
- mov al,0 ; get device info
- int dos
- and dl,81h ; ISDEV and ISCIN bits needed together
- cmp dl,81h ; Console input device?
- jne cnvln7d ; ne = no, use regular file i/o
- push ds
- pop es ; set es:di to datas segment
- push di ; save starting pointer
- cnvln7b:mov ah,coninq ; read console, no echo
- int dos
- stosb
- cmp al,cr ; end of the line yet?
- loopne cnvln7b ; keep reading
- cnvln7c:mov byte ptr [di],0 ; insert terminator
- pop di ; recover starting pointer
- mov dx,di ; simulate read file read
- mov ax,linelen
- sub ax,cx ; ax = number of chars read
- jmp cnvln7e ; close file, finish processing
-
- cnvln7d:mov dx,di ; destination ptr
- mov byte ptr [di],0 ; insert null terminator, clears line
- mov ah,readf2 ; DOS 2 read from file
- int dos
- cnvln7e:pushf ; save flags
- push ax ; save byte count read
- mov ah,close2 ; close file (wanted just one line)
- int dos
- pop ax
- popf ; recover flags now
- jc cnvln8 ; c = error
- mov cx,ax ; ax = number of bytes read
- jcxz cnvln8a ; cx = z = no bytes read
- mov al,cr ; look for cr as terminator
- cld
- repne scasb ; scan while not a cr and cx not zero
- jne cnvln7a ; ne = no cr found
- dec di ; point at cr
- cnvln7a:mov byte ptr [di],0 ; plant terminator on the cr
- ; or after last read char, if no cr.
- pop di ; get original destination ptr
- push di ; and save it again
- mov si,dx ; new source = this line
- ; go convert text, as necessary, and
- jmp cnvln0 ; allow nested indirection
-
- cnvln8: mov ah,prstr
- ; mov dx,offset inderr ; error reading file message
- mcmsg inderr,cinderr
- int dos
- cnvln8a:xor cx,cx ; say zero bytes read
- pop di
- pop si
- stc ; set carry for failure
- ret ; and do a real return
-
- cnvlnx: pop di ; destination ptr
- pop si ; source ptr
- clc ; clear c bit, success
- ret
- cnvlin endp
- ;
- ; worker: read the number of seconds to pause or timeout
- ; returns time of day for timeout in timhms, and next non-space or
- ; non-tab source char ptr in si. Time is either elapsed seconds or
- ; a specific hh:mm:ss, determined from context of colons being present.
- ; Last form can be abbreviated as hh:[mm[:ss]]. Returns carry set if
- ; hh:mm:ss form has bad construction (invalid time).
- inptim proc near
- push ax
- push bx
- push cx
- push dx
- push di
- cld ; decode pure seconds construction
- mov di,si ; remember source pointer
- mov cx,10 ; multiplier
- mov bx,script.indfto ; no numbers yet, use default-timeout
- mov al,byte ptr[si]
- cmp al,':' ; stray hh:mm:ss separator?
- je inptm8 ; e = yes
- cmp al,'9' ; start with numeric input?
- ja inptm4 ; a = no, use default time
- cmp al,'0' ; ditto
- jb inptm4
- xor ah,ah ; source char holder
- xor bx,bx ; accumulated sum
- inptm1: mov al,byte ptr[si] ; get a byte into al
- cmp al,':' ; hh:mm:ss construction?
- je inptm8 ; e = yes
- sub al,'0' ; remove ascii bias
- cmp al,9 ; numeric?
- ja inptm4 ; a = non-numeric, exit loop, bx = sum
- xchg ax,bx ; put sum into ax, char in bl
- mul cx ; sum times ten
- xchg ax,bx ; put char into al, sum in bx
- add bx,ax ; add to sum
- inc si ; next char
- jmp short inptm1 ; loop thru all chars
-
- inptm4: cmp bx,12*60*60 ; half a day, in seconds
- jb inptm5 ; b = less than
- jmp inptm13 ; more than, error
- inptm5: push si ; save ending scan position for return
- mov timout,bx ; # seconds of timeout desired
- mov ah,gettim ; read DOS tod clock
- int dos
- mov timhms[0],ch ; hours
- mov timhms[1],cl ; minutes
- mov timhms[2],dh ; seconds
- mov timhms[3],dl ; hundredths of seconds
- mov bx,2 ; start with seconds field
- inptm6: mov ax,timout ; our desired timeout interval
- add al,timhms[bx] ; add current tod digit to interval
- adc ah,0
- xor dx,dx ; clear high order part thereof
- mov cx,60 ; divide by 60
- div cx ; compute number of minutes or hours
- mov timout,ax ; quotient
- mov timhms[bx],dl ; put remainder in timeout tod digit
- dec bx ; look at next higher order time field
- cmp bx,0 ; done all time fields?
- jge inptm6 ; ge = no
- cmp timhms[0],24 ; normalize hours
- jl inptm7 ; l = not 24 hours
- sub timhms[0],24 ; discard part over 24 hours
- inptm7: pop si ; return ptr to next source char
- jmp inptm11 ; trim trailing whitespace
-
- inptm8: ; decode hh:[mm[:ss]] to timhms
- mov si,di ; recall starting source pointer
- mov word ptr timhms[0],0 ; clear time out tod
- mov word ptr timhms[2],0
- mov bx,0 ; three groups possible
- inptm9: mov dl,byte ptr[si] ; get a char
- cmp dl,':' ; field separator?
- je inptm10 ; e = a separator, step fields
- sub dl,'0' ; remove ascii bias
- cmp dl,9
- ja short inptm11 ; a = failure to get expected digit
- mov al,timhms[bx] ; get sum to al
- mov ah,10
- mul ah ; sum times ten
- add al,dl ; sum = 10 * previous + current
- mov timhms[bx],al ; current sum
- cmp timhms[bx],60 ; more than legal?
- jae inptm13 ; ae = illegal
- cmp bx,0 ; doing hours?
- ja inptm9a ; a = no, min or sec
- cmp timhms[bx],24 ; more than legal?
- jae inptm13 ; ae = illegal
- inptm9a:inc si ; next char
- jmp short inptm9 ; continue analysis
- inptm10:inc bx ; point to next field
- inc si ; next char
- cmp bx,2 ; last subscript to use (secs)
- jbe inptm9 ; be = get more text
-
- inptm11:cmp byte ptr [si],spc ; examine break char, remove spaces
- jne inptm12 ; ne = no, stay at this char
- inc si ; look at next char
- jmp short inptm11 ; continue scanning off white space
- inptm12:clc ; carry clear for success
- jnc inptm14
- inptm13:stc ; carry set for illegal value
- inptm14:pop di ; return with si beyond our text
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- inptim endp
-
- ; worker: display the char in al on screen
- ; use caret-char notation for control codes
- scdisp proc near
- push dx
- push ax
- mov ah,conout ; our desired function
- test flags.remflg,d8bit ; show all 8 bits?
- jnz scdisp0 ; nz = yes
- and al,7fh ; apply 7 bit display mask
- scdisp0:cmp al,0 ; null?
- je scdis2 ; e = yes, ignore
- cmp al,del ; delete code?
- je scdis2 ; e = yes, ignore
- cmp al,spc ; control char?
- jae scdis1 ; ae = no, display as-is
- cmp al,cr ; carriage return?
- je scdis1 ; e = yes, display as-is
- cmp al,lf ; line feed?
- je scdis1
- cmp al,tab ; horizontal tab?
- je scdis1
- cmp al,bell ; bell?
- je scdis1
- cmp al,bs ; backspace?
- je scdis1
- cmp al,escape ; escape?
- je scdis1
- or al,40h ; control code to printable char
- push ax
- mov dl,5eh ; display caret first
- int dos
- pop ax
- scdis1: mov dl,al ; the char to be displayed
- int dos
- scdis2: pop ax
- pop dx
- ret
- scdisp endp
-
- ; workers
- ; Circular buffer for data from serial port. Written by Joe R. Doupnik
- ; Entry points -
- ; bufread: read serial port for latest char (invokes bufwrite, sets
- ; status), get a char into al, return carry set if none.
- ; bufwrite: put a char from al into buf. If this overwrites an unread
- ; character then: we lose the old char, the read pointer
- ; is moved to the next oldest unread char, and the
- ; number of chars in the buffer is decreased by one.
- ; bufclear: empties the buffer.
- ; The buffer is prtbuf, of size prtbuflen bytes. Internally, integer bufcnt
- ; holds the number of buffer locations occupied, pointer bufrdptr is the
- ; offset of the char to be read, pointer bufwtptr is the offset of the
- ; place to store the next incoming char.
- ;
- bufclear proc near
- mov bufcnt,0 ; clear count of bytes in buffer
- mov bufrdptr,offset prtbuf ; move read pointer to start of buf
- mov bufwtptr,offset prtbuf ; move write pointer to start of buf
- mov cx,prtbuflen
- push es ; physically clear the buffer
- push di
- mov ax,datas
- mov es,ax
- mov al,0 ; write prtbuflen nulls
- mov di,offset prtbuf
- cld
- rep stosb
- pop di
- pop es
- ret
- bufclear endp
-
- bufread proc near
- call chkport ; get any oldest char from port
- cmp bufcnt,0 ; empty buffer?
- jne bufrd1 ; ne = no
- stc ; yes, set carry flag (no char)
- ret ; and quit (chkport sets status)
- bufrd1: push si
- mov si,bufrdptr
- mov al,byte ptr [si] ; extract a char into al
- pop si
- inc bufrdptr ; move pointer to next byte
- dec bufcnt ; say have extracted a char
- cmp bufrdptr,offset prtbuf+prtbuflen ; beyond end?
- jb bufrd2 ; b = not yet, just return
- mov bufrdptr,offset prtbuf ; reset to start of buf (wrapping)
- bufrd2: clc ; clear carry flag (have read a char)
- ret ; chkport sets status
- bufread endp
-
- ; Non-destructive read of serial port circular buffer. Requires external
- ; initialization of peek read pointer bufpkptr and count remaining bufpkcnt.
- ; Returns character in register al.
- peekbuf proc near
- cmp bufpkcnt,0 ; peek counter, empty buffer?
- jne peekbu2 ; ne = no, so look in buffer
- cmp bufcnt,prtbuflen ; is real buffer full?
- jae peekbu1 ; ae = yes, have examined everything
- call chkport ; get a char from port
- cmp bufcnt,0 ; still nothing from port?
- je peekbu1 ; e = no char, report fact
- inc bufpkcnt ; got one, increase peek counter
- jmp peekbu2 ; go extract it
- peekbu1:stc ; return nothing to see
- ret
- peekbu2:push si
- mov si,bufpkptr ; buffer peek pointer
- mov al,byte ptr [si] ; extract a char into al
- pop si
- inc bufpkptr ; move pointer to next byte
- dec bufpkcnt ; say have extracted a char
- cmp bufpkptr,offset prtbuf+prtbuflen ; beyond end?
- jb peekbu3 ; b = not yet, just return
- mov bufpkptr,offset prtbuf ; reset to start of buf (wrapping)
- peekbu3:clc ; clear carry flag (have read a char)
- ret
- peekbuf endp
-
- bufwrite proc near
- push si
- mov si,bufwtptr
- mov byte ptr [si],al ; store char held in al
- pop si
- inc bufwtptr ; move pointer to next byte
- cmp bufwtptr,offset prtbuf+prtbuflen ; beyond end?
- jb bufwt1 ; b = not yet
- mov bufwtptr,offset prtbuf ; reset to start of buf (wrapping)
- bufwt1: inc bufcnt ; say have added a char to the buf
- cmp bufcnt,prtbuflen ; more than we can hold?
- jbe bufwt3 ; be = not overflowing
- push bufwtptr ; read ptr can't alias write ptr
- pop bufrdptr ; move up read pointer
- mov bufcnt,prtbuflen ; limit count to max buffer length
- bufwt3: ret
- bufwrite endp
-
- ; worker: check for timeout, return status=stat_tmo if timeout, else bit
- ; stat_tmo is cleared.
- chktmo: and status,not stat_tmo
- mov ah,gettim ; get the time of day
- int dos
- sub ch,timhms[0] ; hours difference, ch = (now-timeout)
- je chktmo2 ; e = same, check mmss.s
- jg chktmo1 ; g = past target hour
- add ch,24 ; we are early, see by how much
- chktmo1:cmp ch,12 ; hours difference, large or small?
- jge chktmox ; ge = not that time yet
- jl chktmo3 ; l = beyond that time
- chktmo2:cmp cl,timhms[1] ; minutes, hours match
- jb chktmox ; b = early
- ja chktmo3 ; a = late
- cmp dh,timhms[2] ; seconds, hhmm match
- jb chktmox ; b = early
- ja chktmo3 ; a = late
- cmp dl,timhms[3] ; fractions, hhmmss match
- jb chktmox ; b = early
- chktmo3:or status,stat_tmo ; say timeout
- stc
- ret
- chktmox:clc
- ret
- ;
- ; worker: check keyboard for char. Return status = stat_cc if control-C typed,
- ; stat_cr if carriage return, or stat_ok if any other char typed. Else return
- ; with these status bits cleared.
- chkkbd: and status,not (stat_ok+stat_cc+stat_cr) ; clear status bits
- cmp flags.cxzflg,'C' ; Control-C interrupt seen?
- je chkkbd0 ; e = yes
- call isdev ; is stdin a device, not disk file?
- jnc chkkbd2 ; nc = not device so do not read here
- mov ah,dconio ; keyboard char present?
- mov dl,0ffH
- int dos
- je chkkbd1 ; e = none
- or status,stat_ok ; have a char, return it in al
- cmp al,3 ; control c?
- jne chkkbd1 ; ne = not control c
- chkkbd0:or status,stat_cc ; say control c
- chkkbd1:cmp al,cr ; carriage return? [js]
- jne chkkbd2 ; ne = no
- or status,stat_cr ; say carriage return [js]
- chkkbd2:ret
- ;
- ; worker: check serial port for received char. Return status = stat_ok if
- ; char received, otherwise stat_ok cleared. Can echo char to screen. Will
- ; write char to local circular buffer.
- chkport:and status,not stat_ok ; clear status bit
- call prtchr ; char at port (in al)?
- jmp chkpor1 ; yes, analyze it
- nop ; ensure 3 bytes for rskp of prtchr
- ret ; no, return
- chkpor1:and al,parmsk ; strip parity, if any
- cmp rxtable+256,0 ; is translation turned off?
- je chkpor0 ; e = yes, no translation
- push bx ; translate incoming character
- mov bx,offset rxtable ; the translation table
- xlatb
- pop bx
- chkpor0:test flags.capflg,logses ; capturing active?
- jz chkpor3 ; z = no
- test flags.remflg,d8bit ; keep 8 bits for displays?
- jnz chkpo0a ; nz = yes, 8 bits if possible
- cmp flags.debug,0 ; is debug mode active?
- jne chkpo0a ; ne = yes, record 8 bits
- and al,7fh ; remove high bit
- chkpo0a:push ax ; save char
- call cptchr ; give it captured character
- pop ax ; restore character and keep going
- chkpor3:test flags.remflg,d8bit ; keep 8 bits for displays?
- jnz chkpo3a ; nz = yes, 8 bits if possible
- and al,7fh ; remove high bit
- chkpo3a:cmp script.inecho,0 ; input echoing off?
- je chkpor4 ; e = yes
- call scdisp ; display the char
- chkpor4:call bufwrite ; put char in buffer
- or status,stat_ok ; say have a char (still in al)
- ret
- ;
- ; Squit is the script error exit pathway.
- ;
- squit: mov kstatus,2 ; general command status, failure
- test status,stat_tmo ; timeout?
- jz squit2 ; z = no, another kind of failure
- cmp taklev,0 ; in a Take/macro?
- jne squit1 ; ne = yes, skip timeout message
- push dx
- ; mov dx,offset tmomsg ; say timed out
- mcmsg tmomsg,ctmomsg
- mov ah,prstr
- int dos ; display it.
- pop dx
- squit1: cmp script.inactv,0 ; action to do upon timeout
- je squit4 ; 0 = proceed, ne = non-zero = quit
- call takclos ; close Take file or macro
- squit2: call isdev ; stdin is a device (vs file)?
- jc squit3 ; c = device, not a file
- mov flags.extflg,1 ; set Kermit exit flag
- squit3: ret ; return failure
- squit4: jmp rskp ; return success, ignore error
-
- ;
- ; Jumping to this location is like retskp. It assumes the instruction
- ; after the call is a jmp addr.
-
- RSKP PROC NEAR
- pop bp
- add bp,3
- push bp
- ret
- RSKP ENDP
-
- ; Jumping here is the same as a ret.
-
- R PROC NEAR
- ret
- R ENDP
-
- code ends
- end
-